﻿
//#define USE_WEAK_REFERENCE

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class EventDispatcher
{
	internal class WeakPtr
	{
		public WeakPtr( EventHandlerPool aEpool, EventHandler aHandler)
		{
			epool = aEpool;
			epool.eventHandlers += OnEvent;

			wr = new System.WeakReference(aHandler.Target);
			methodInfo = aHandler.Method;
		}

		List<WeakPtr> wpList;
		EventHandlerPool epool;
		System.WeakReference wr;
		System.Reflection.MethodInfo methodInfo;
		static System.Object[] args = new System.Object[1];

		public void OnEvent(BaseEvent e)
		{
			if (wr.Target  != null || methodInfo.IsStatic)
			{
				args[0] = e;
				methodInfo.Invoke(wr.Target, args);
			}
			else{
				epool.eventHandlers -= OnEvent;
				epool = null;
				wr = null;
				methodInfo = null;
			}
		}
	}

	internal class EventHandlerPool
	{
		public event EventHandler eventHandlers;
		
		public void dispatchEvent (BaseEvent e)
		{
			if (!isEmpty ()) {
				eventHandlers (e);
			}
		}
		
		public bool isEmpty ()
		{
			return (null == eventHandlers);
		}
	}
	
	Dictionary <string,  EventHandlerPool> mapEventHandler = new Dictionary<string, EventHandlerPool> ();
	
	public void removeEventListener (string astrEventName, EventHandler listener)
	{	
		if (mapEventHandler.ContainsKey (astrEventName)) {
			EventHandlerPool eventHandlerPool = mapEventHandler [astrEventName];
			eventHandlerPool.eventHandlers -= listener;
			if (eventHandlerPool.isEmpty ()) {
				mapEventHandler.Remove (astrEventName);
			}
		} 
	}
	
	public bool hasEventListener (string astrEventName)
	{
		return mapEventHandler.ContainsKey (astrEventName);
	}
	
	public void addEventListener (string astrEventName, EventHandler listener)
	{
		
		if (!mapEventHandler.ContainsKey (astrEventName))
		{
			mapEventHandler [astrEventName] = new EventHandlerPool ();
		}  

#if USE_WEAK_REFERENCE
		new WeakPtr(mapEventHandler[astrEventName], listener);
#else
		mapEventHandler[astrEventName].eventHandlers += listener;
#endif
	}
	
	public bool dispatchEvent (BaseEvent e)
	{
		if (mapEventHandler.ContainsKey (e.strName)) {
			mapEventHandler [e.strName].dispatchEvent (e);
		} 
		return true;
	}
}
